﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Resources;
using System.Data.SqlClient;
using System.Xml;
using System.IO;

using XEvents.Library;
using XEvents.Library.Targets;
using System.Runtime.InteropServices;
using System.Reflection;
using Microsoft.SqlServer.Management.UI.VSIntegration;
using Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer;
using EnvDTE;
using EnvDTE80;

namespace XEvents.Addin
{
    [Guid("E9B27AE4-24C3-4F24-B010-85FCA0090024")]
    public partial class XEventSessionExplorer : UserControl
    {
        private string currentServerName = string.Empty;
        private List<SqlServer> servers = new List<SqlServer>();
        
        public void AddServer(SqlServer server)
        {
            this.servers.Add(server);
            BindTreeView(server);
        }

        public XEventSessionExplorer()
        {
            InitializeComponent();
            SSMSAddinHelper.GetOpenWindow("test");
            this.Leave += new EventHandler(XEventSessionExplorer_Leave);
        }

        void XEventSessionExplorer_Leave(object sender, EventArgs e)
        {
            object[] obj = new object[0];
            SSMSAddinHelper.XEventSessionExplorer.SetSelectionContainer(ref obj);
        }

        void Provider_SelectionChanged(object sender, NodesChangedEventArgs args)
        {
            UpdateExplorerInfo();
        }

        private void UpdateExplorerInfo()
        {
            // Nothing selected
            if (SSMSAddinHelper.ObjectExplorerSelectedNode == null)
                return;

            // Don't fire if Server wasn't changed.
            if (currentServerName == SSMSAddinHelper.ObjectExplorerSelectedNode.Connection.ServerName)
                return;

            this.treeView1.Nodes.Clear();
            this.servers.Clear();

            currentServerName = SSMSAddinHelper.ObjectExplorerSelectedNode.Connection.ServerName;
            XEvents.Library.SqlServer server;

            try
            {
                if (SSMSAddinHelper.ObjectExplorerSelectedNode.Connection.UseIntegratedSecurity)
                    server = new XEvents.Library.SqlServer(SSMSAddinHelper.ObjectExplorerSelectedNode.Connection.ServerName);
                else
                    server = new XEvents.Library.SqlServer(SSMSAddinHelper.ObjectExplorerSelectedNode.Connection.ServerName, SSMSAddinHelper.ObjectExplorerSelectedNode.Connection.UserName, SSMSAddinHelper.ObjectExplorerSelectedNode.Connection.Password);
            }
            catch
            {
                return;
            }
            this.AddServer(server);
        }

        private void BindTreeView(SqlServer server)
        {
            XmlDocument xdoc = server.GetSessionXml();
            System.Diagnostics.Debug.WriteLine(xdoc.InnerXml);
            TreeNode tNode = new TreeNode();

            if (!treeView1.Nodes.ContainsKey(server.ServerName))
            {
                treeView1.Nodes.Add(new XEventTreeNode(server.ServerName, xdoc.DocumentElement));
            }

            tNode = treeView1.Nodes.Find(server.ServerName, false).ElementAt(0);

            tNode.Nodes.Clear();

            // SECTION 3. Populate the TreeView with the DOM nodes.
            AddNode(xdoc.DocumentElement, tNode);
            treeView1.Nodes[0].Expand();

        }
        private void AddNode(XmlNode inXmlNode, TreeNode inTreeNode)
        {
            XmlNode xNode;
            TreeNode tNode;
            XmlNodeList nodeList;
            int i;

            // Loop through the XML nodes until the leaf is reached.
            // Add the nodes to the TreeView during the looping process.
            if (inXmlNode.HasChildNodes)
            {
                nodeList = inXmlNode.ChildNodes;
                for (i = 0; i <= nodeList.Count - 1; i++)
                {
                    xNode = inXmlNode.ChildNodes[i];
                    if (xNode.Attributes == null)
                        inTreeNode.Nodes.Add(new XEventTreeNode(xNode.Name, xNode));
                    else if (xNode.Attributes["Name"] == null)
                        inTreeNode.Nodes.Add(new XEventTreeNode(xNode.Name, xNode));
                    else
                    {
                        XEventTreeNode xetn = new XEventTreeNode(xNode.Attributes["Name"].Value, xNode);
                        inTreeNode.Nodes.Add(xetn);
                    }
                    tNode = inTreeNode.Nodes[i];
                    AddNode(xNode, tNode);
                }
            }
            else
            {

                // Here you need to pull the data from the XmlNode based on the
                // type of node, whether attribute values are required, and so forth.

                if (inXmlNode.Attributes == null || inXmlNode.Attributes["Name"] == null)
                    inTreeNode.Text = inXmlNode.Name;
                else
                {
                    inTreeNode.Text = inXmlNode.Attributes["Name"].Value;
                }
            }

        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            TreeNode tNode = e.Node;
            XmlNode xnode = (XmlNode)tNode.Tag;

            string nodeInfo = string.Empty;

            if (xnode != null)
            {
                if (xnode.ParentNode.Name == "Value")
                {
                    nodeInfo = xnode.Value;
                }
                else
                {
                    foreach (XmlAttribute xa in xnode.Attributes)
                    {
                        nodeInfo += xa.Name + ": " + xa.Value + "\r\n";
                    }
                }
                
                object[] obj = new object[0];
                if (!(this.SelectedSession == null))
                    obj = new object[] { this.SelectedSession };

                SSMSAddinHelper.XEventSessionExplorer.SetSelectionContainer(ref obj);
            }
        }

        private void BindSelectedNodeProperties()
        {
            TreeNode tnode = treeView1.SelectedNode;

        }
        private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            contextMenuStrip1.Items.Clear();
            treeView1.SelectedNode = e.Node;
            XmlNode xNode = (XmlNode)e.Node.Tag;
            if (e.Button == MouseButtons.Right)
            {
                if (e.Node.Level == 0)
                {
                    GenerateServerMenu();
                }
                else if (xNode.Name == "EventSession")
                {
                    GenerateSessionMenu(xNode);
                }
                else if (xNode.Name == "EventSessionTarget")
                {
                    ToolStripMenuItem tsmi;

                    tsmi = new ToolStripMenuItem("View Target Data");
                    tsmi.Click += new EventHandler(ViewTargetData_Click);
                    tsmi.Enabled = (xNode.ParentNode.ParentNode.Attributes["SessionState"].Value == "Start");

                    contextMenuStrip1.Items.Add(tsmi);

                    tsmi = new ToolStripMenuItem("Query Target Data with TSQL");
                    tsmi.Click += new EventHandler(QueryTargetDataTSQL_Click);
                    tsmi.Enabled = (xNode.ParentNode.ParentNode.Attributes["SessionState"].Value == "Start");

                    contextMenuStrip1.Items.Add(tsmi);

                }
                contextMenuStrip1.Show(treeView1, e.Location);
            }

        }

        private void GenerateServerMenu()
        {
            ToolStripMenuItem tsmi = new ToolStripMenuItem("New Event Session");
            tsmi.Click += new EventHandler(NewEventSession_Click);
            contextMenuStrip1.Items.Add(tsmi);

            contextMenuStrip1.Items.Add(new ToolStripSeparator());

            tsmi = new ToolStripMenuItem("Refresh");
            tsmi.Click += new EventHandler(Refresh_Click);
            contextMenuStrip1.Items.Add(tsmi);

            contextMenuStrip1.Items.Add(new ToolStripSeparator());

            tsmi = new ToolStripMenuItem("View XEvent Metadata");
            tsmi.Click += new EventHandler(ViewMetadataControl_Click);
            contextMenuStrip1.Items.Add(tsmi);


            contextMenuStrip1.Items.Add(new ToolStripSeparator());

            tsmi = new ToolStripMenuItem("Addin Options");
            tsmi.Click += new EventHandler(AddinOptions_Click);
            contextMenuStrip1.Items.Add(tsmi);

        }

        void AddinOptions_Click(object sender, EventArgs e)
        {
            OptionEditorForm oef = new OptionEditorForm();
            oef.ShowDialog();
        }

        private void GenerateSessionMenu(XmlNode xNode)
        {
            ToolStripMenuItem tsmi;
            ToolStripMenuItem subtsmi;

            tsmi = new ToolStripMenuItem("Edit Event Session");
            tsmi.Click += new EventHandler(EditEventSession_Click);
            contextMenuStrip1.Items.Add(tsmi);

            contextMenuStrip1.Items.Add(new ToolStripSeparator());
            
            tsmi = new ToolStripMenuItem("Drop Event Session");
            tsmi.Click += new EventHandler(DropEventSession_Click);
            contextMenuStrip1.Items.Add(tsmi);

            contextMenuStrip1.Items.Add(new ToolStripSeparator());

            tsmi = new ToolStripMenuItem("Script Session as");
            
            subtsmi = new ToolStripMenuItem("CREATE to");
            subtsmi.DropDownItems.Add(new ToolStripMenuItem("File", null, new EventHandler(ScriptToFile_Click)));
            subtsmi.DropDownItems.Add(new ToolStripMenuItem("Clipboard", null, new EventHandler(ScriptToClipboard_Click)));
            subtsmi.DropDownItems.Add(new ToolStripMenuItem("New SSMS Window", null, new EventHandler(ScriptToSSMS_Click)));
            tsmi.DropDownItems.Add(subtsmi);

            subtsmi = new ToolStripMenuItem("DROP to");
            subtsmi.DropDownItems.Add(new ToolStripMenuItem("File", null, new EventHandler(ScriptToFile_Click)));
            subtsmi.DropDownItems.Add(new ToolStripMenuItem("Clipboard", null, new EventHandler(ScriptToClipboard_Click)));
            subtsmi.DropDownItems.Add(new ToolStripMenuItem("New SSMS Window", null, new EventHandler(ScriptToSSMS_Click)));
            tsmi.DropDownItems.Add(subtsmi);


            contextMenuStrip1.Items.Add(tsmi);
            contextMenuStrip1.Items.Add(new ToolStripSeparator());
            
            tsmi = new ToolStripMenuItem("Start Event Session");
            tsmi.Click += new EventHandler(StartEventSession_Click);
            if (xNode.Attributes["SessionState"] != null)
            {
                tsmi.Enabled = !(xNode.Attributes["SessionState"].Value == "Start");
            }
            contextMenuStrip1.Items.Add(tsmi);
            
            tsmi = new ToolStripMenuItem("Stop Event Session");
            tsmi.Click += new EventHandler(StopEventSession_Click);
            if (xNode.Attributes["SessionState"] != null)
            {
                tsmi.Enabled = (xNode.Attributes["SessionState"].Value == "Start");
            }
            contextMenuStrip1.Items.Add(tsmi);

        }

        #region Session Events

        private void ChangeSessionState(EventSession session, SessionState State)
        {
            try
            {
                session.ChangeSessionState(State);

                // TODO: Fix this to remove current node 
                ReloadNode(session.SqlServer.ServerName, session.Name);
                //Load_Form();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "An Error Occured!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void DropEventSession(EventSession ses)
        {
            try
            {
                ses.DropEventSession();

                // TODO: Fix this to remove current node 
                RemoveNode(ses.SqlServer.ServerName, ses.Name);
                //Load_Form();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "An Error Occured!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion

        #region Menu Click Events

        Window[] windows = new Window[10];

        private string ToolWindowName
        {
            get
            {
                return string.Format("[{0}] {1} ({2})", this.CurrentServer.ServerName, this.SelectedSession.Name, this.SelectedTarget.Name);
            }
        }

        bool CodeGenObjectsExist(CodeGenConfiguration cgc)
        {
            bool exists = false;
            if (!(cgc.ServerName == string.Empty))
            {
                string fn_check = @"DECLARE @fn_exists bit;
SELECT @fn_exists = 1 FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'xe_code_generator';
SELECT isnull(@fn_exists, 0) as fn_exists;";

                using (SqlConnection conn = new SqlConnection(SSMSAddinHelper.ObjectExplorerSelectedNode.Connection.ConnectionString))
                {
                    using (SqlCommand cmd = new SqlCommand(fn_check, conn))
                    {
                        conn.Open();
                        try
                        {
                            conn.ChangeDatabase(cgc.DatabaseName);
                            using (SqlDataReader dr = cmd.ExecuteReader())
                            {
                                bool fn_exists = false;
                                while (dr.Read())
                                {
                                    fn_exists = dr.GetBoolean(0);
                                }
                                    exists = fn_exists; 
                            }
                        }
                        catch 
                        {  }

                        if (conn.State != ConnectionState.Closed)
                            conn.Close();
                    }
                }
            }
            return exists;
        }

        void QueryTargetDataTSQL_Click(object sender, EventArgs e)
        {
            if (Properties.Settings.Default.CodeGenSettings == null)
                Properties.Settings.Default.CodeGenSettings = new CodeGenConfigurations();

            CodeGenConfiguration cgc = Properties.Settings.Default.CodeGenSettings[this.SelectedSession.SqlServer.ServerName] == null ? new CodeGenConfiguration() : Properties.Settings.Default.CodeGenSettings[this.SelectedSession.SqlServer.ServerName];

            if (!CodeGenObjectsExist(cgc))
            {
                if (cgc.ServerName == string.Empty || cgc.ServerName == null)
                    cgc.ServerName = this.SelectedSession.SqlServer.ServerName;

                CodeGenerator cg = new CodeGenerator(cgc);
                DialogResult diagres = cg.ShowDialog();
                if (diagres == DialogResult.Cancel)
                    return;
                else
                {
                    if (Properties.Settings.Default.CodeGenSettings[cgc.ServerName] == null)
                    {
                        Properties.Settings.Default.CodeGenSettings.Add(cgc);
                    }

                    Properties.Settings.Default.Save();
                }
            }

            using (SqlConnection conn = new SqlConnection(SSMSAddinHelper.ObjectExplorerSelectedNode.Connection.ConnectionString))
            {
                using (SqlCommand cmd = new SqlCommand(string.Format("select dbo.xe_code_generator('{0}', '{1}')", this.SelectedSession.Name, this.SelectedTarget.Name.Split('.').ElementAt(1)), conn))
                {
                    conn.Open();
                    try
                    {
                        conn.ChangeDatabase(cgc.DatabaseName);

                        using (SqlDataReader dr = cmd.ExecuteReader())
                        {
                            string code = string.Empty;
                            while (dr.Read())
                                code = dr[0].ToString();

                            code = code.Substring(10);
                            code = code.Substring(0, code.Length - 4);

                            code = string.Format(contextSQLcmd, cgc.DatabaseName) + code;

                            // create new document
                            ServiceCache.ScriptFactory.CreateNewBlankScript(Microsoft.SqlServer.Management.UI.VSIntegration.Editors.ScriptType.Sql);
                            // insert SQL definition to document
                            EnvDTE.TextDocument doc = (EnvDTE.TextDocument)ServiceCache.ExtensibilityModel.Application.ActiveDocument.Object(null);
                            doc.EndPoint.CreateEditPoint().Insert(code);
                        }
                    }
                    catch (Exception ex)
                    { }

                    if (conn.State != ConnectionState.Closed)
                        conn.Close();
                }

            }
        }

        private readonly string contextSQLcmd = @"USE [{0}];" + Environment.NewLine + "GO" + Environment.NewLine;

        void ViewTargetData_Click(object sender, EventArgs e)
        {
            foreach (EnvDTE80.Window2 w in (EnvDTE80.Windows2)ServiceCache.ExtensibilityModel.DTE.Windows)
            {
                if (w.Caption == ToolWindowName)
                {
                    w.Activate();
                    ((TargetDataViewer_Control)w.Object).ReloadData();
                    return;
                }
            }

            string id = null;
            int i = 0;
            int j = 0;
            for (i = 0; i < windows.Length; i++)
            {
                if (windows[i] != null)
                {
                    if (!windows[i].Visible)
                    {
                        id = SSMSAddinHelper.ToolWindowGuids[i]; 
                        break;
                    }
                   
                    if (windows[i].Caption.Split(" ".ToCharArray()).ElementAt(2).Trim(new char[] { '(', ')' }) == this.SelectedTarget.Name)
                        j++;

                    if (j == 3)
                    {
                        MessageBox.Show(string.Format("To many Target Viewers for target type {0} are open.\r\nClose one and then retry the operation.", this.SelectedTarget.Name));
                        return;
                    }

                }
                else
                {
                    id = SSMSAddinHelper.ToolWindowGuids[i];
                    break;
                }
            }

            if (id == null)
            {
                MessageBox.Show("To many Target Viewers Open. Close one and then retry the operation.");
                return;
            }

            TargetData td = this.SelectedTarget.TargetData;

            EnvDTE.Window toolwindow = SSMSAddinHelper.CreateToolWindow("XEvents.Addin.TargetDataViewer_Control", new Guid("{" + id + "}"), ToolWindowName);
            ((TargetDataViewer_Control)toolwindow.Object).Init(td);

            windows[i] = toolwindow;
        }


        void StartEventSession_Click(object sender, EventArgs e)
        {
            DialogResult dr = MessageBox.Show("Are you sure you want to start collection for the " + this.SelectedSession.Name + " session?", "Start Session Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (dr == DialogResult.Yes)
            {
                ChangeSessionState(this.SelectedSession, SessionState.Start);
            }
        }
        void StopEventSession_Click(object sender, EventArgs e)
        {
            DialogResult dr = MessageBox.Show("Are you sure you want to stop collection for the " + this.SelectedSession.Name + " session?", "Stop Session Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (dr == DialogResult.Yes)
            {
                //bool tdv_found = false;
                //foreach (IDockContent idoc in this.DockPanel.Documents)
                //{
                //    if (idoc is TargetDataViewer)
                //    {
                //        TargetDataViewer tdv = (TargetDataViewer)idoc;

                //        foreach (TreeNode tn in treeView1.SelectedNode.Nodes["Targets"].Nodes)
                //        {
                //            if (tdv.TabText == "[" + this.CurrentServer.ServerName + "] " + tn.Name)
                //            {
                //                tdv.BringToFront();
                //                tdv.SessionStopped();
                //                tdv_found = true;
                //            }
                //        }
                //    }
                //}
                //if (tdv_found)
                //    MessageBox.Show("The Session has been stopped.  Updates are no longer available.\r\n\r\nTo resume updating data, close the Target Viewer, restart the Event Session and then reopen the Target Viewer.", "Event Session Stop Notification!", MessageBoxButtons.OK, MessageBoxIcon.Information);

                ChangeSessionState(this.SelectedSession, SessionState.Stop);
            }
        }

        void ScriptToFile_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem tsmi = (ToolStripMenuItem)sender;
            string script = string.Empty;
            switch (tsmi.OwnerItem.Text)
            {
                case "CREATE to":
                    script = this.SelectedSession.GenerateSQLScript();
                    break;
                case "DROP to":
                    script = this.SelectedSession.GenerateDropScript();
                    break;
            }
            WriteTextToFile(script);
        }

        public void WriteTextToFile(string text)
        {
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.AddExtension = true;
            saveFileDialog1.DefaultExt = ".sql";

            DialogResult dr = saveFileDialog1.ShowDialog();
            if (dr != DialogResult.Cancel && saveFileDialog1.FileName != null && saveFileDialog1.FileName != string.Empty)
            {
                System.IO.Stream s = saveFileDialog1.OpenFile();
                StreamWriter sw = new StreamWriter(s);
                sw.Write(text);
                sw.Flush();
                s.Flush();
                sw.Close();
                s.Close();
            }
        }

        void ScriptToClipboard_Click(object sender, EventArgs e)
        {
            
            ToolStripMenuItem tsmi = (ToolStripMenuItem)sender;

            string script = string.Empty;
            switch (tsmi.OwnerItem.Text)
            {
                case "CREATE to":
                    script = this.SelectedSession.GenerateSQLScript();
                    break;
                case "DROP to":
                    script = this.SelectedSession.GenerateDropScript();
                    break;
            }
            try
            {
                Clipboard.SetText(script);
            }
            catch
            {
                MessageBox.Show("An Exception Occured copying the script to the Clipboard.\r\n\r\nThis error occurs most often on Virtual machines with the vmusrvc.exe addin running.\r\nIf this problem persists, stop/kill this addin and try again.\r\nFor further information please see http://www.windowsvistaplace.com/clipboard-chaos/virtual-pc.", "Clipboard Failure", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void ScriptToSSMS_Click(object sender, EventArgs e)
        {

            ToolStripMenuItem tsmi = (ToolStripMenuItem)sender;

            string script = string.Empty;
            switch (tsmi.OwnerItem.Text)
            {
                case "CREATE to":
                    script = this.SelectedSession.GenerateSQLScript();
                    break;
                case "DROP to":
                    script = this.SelectedSession.GenerateDropScript();
                    break;
            }

            // create new document
            ServiceCache.ScriptFactory.CreateNewBlankScript(Microsoft.SqlServer.Management.UI.VSIntegration.Editors.ScriptType.Sql);
            // insert SQL definition to document
            EnvDTE.TextDocument doc = (EnvDTE.TextDocument)ServiceCache.ExtensibilityModel.Application.ActiveDocument.Object(null);
            doc.EndPoint.CreateEditPoint().Insert(script);

        }

        void EditEventSession_Click(object sender, EventArgs e)
        {
            SessionEditorForm editor = new SessionEditorForm(this.SelectedSession, false);
            editor.Show();
        }

        private EventSession SelectedSession
        {
            get
            {
                if (treeView1.SelectedNode == null)
                    return null;

                TreeNode tn = GetParentNodeByLevel(treeView1.SelectedNode, 1);

                if (tn == null)
                    return null;

                return CurrentServer.EventSessions[tn.Name];

            }
        }

        private EventSessionTarget SelectedTarget
        {
            get
            {
                TreeNode tn = treeView1.SelectedNode;
                TreeNode pn = tn.Parent.Parent;
                return CurrentServer.EventSessions[pn.Text].Targets[tn.Text];
            }
        }

        private SqlServer CurrentServer
        {
            get
            {
                TreeNode tn = GetParentNodeByLevel(treeView1.SelectedNode, 0);

                if (tn == null)
                    return null;

                return servers.ToDictionary(s => s.ServerName, s => s)[tn.Name];
            }
        }


        void DropEventSession_Click(object sender, EventArgs e)
        {

            DialogResult dr = MessageBox.Show("Are you sure you want to drop the " + this.SelectedSession.Name + " session?\r\n\r\nThe current Session State is "+this.SelectedSession.SessionState.ToString()+".", "Drop Session Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (dr == DialogResult.No)
                return;

            if (this.SelectedSession.SessionState == SessionState.Start && Properties.Settings.Default.DropActiveWarning)
            {
                dr = MessageBox.Show(this.SelectedSession.Name + " is an Active Session?\r\n\r\nAre you certain you want to drop it?", "Drop Active Session Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (dr == DialogResult.No)
                    return;
            }

            DropEventSession(this.SelectedSession);
        }
        

        void NewEventSession_Click(object sender, EventArgs e)
        {
            EventSession ses = new EventSession(CurrentServer);

            // Override Session Defaults if configured to do so.
            if (Properties.Settings.Default.OverrideDefaultOptions)
            {
                ses.EventRetentionMode = Properties.Settings.Default.EventRetentionMode;
                ses.MaxDispatchLatency = Properties.Settings.Default.MaxDispatchLatency;
                ses.MaxEventSize = Properties.Settings.Default.MaxEventSize;
                ses.MaxMemory = Properties.Settings.Default.MaxMemory;
                ses.MemoryPartitionMode = Properties.Settings.Default.MemoryPartitionMode;
                ses.StartupState = Properties.Settings.Default.StartupState;
                ses.TrackCausality = Properties.Settings.Default.TrackCausality;
            }

            SessionEditorForm editor = new SessionEditorForm(ses, true);
            editor.Show();
        }

        void Refresh_Click(object sender, EventArgs e)
        {
            Load_Form();
        }



        void ViewMetadataControl_Click(object sender, EventArgs e)
        {
            EnvDTE.Window toolwindow = SSMSAddinHelper.CreateToolWindow("XEvents.Addin.MetaDataViewerForm_Control", new Guid("406222D6-A9A4-4F5D-9DC8-587478374DB3"), "Extended Events Metadata Viewer (" + currentServerName + ")");
            ((MetaDataViewerForm_Control)toolwindow.Object).Initialize(CurrentServer);
        }

        #endregion

        public void Load_Form()
        {
            if (servers.Count > 0)
            {
                foreach (SqlServer server in servers)
                {
                    server.Refresh();
                    BindTreeView(server);
                    treeView1.Nodes[0].Expand();
                }
            }
        }

        public void RefreshSelectedItem()
        {
            ReloadNode(GetParentNodeByLevel(treeView1.SelectedNode, 1));
        }

        private TreeNode GetParentNodeByLevel(TreeNode tn, int level)
        {
            if (level == tn.Level)
                return tn;

            if (level > tn.Level || tn.Parent == null)
                return null;

            TreeNode parent = tn.Parent;
            while (parent.Level > level)
            {
                parent = parent.Parent;
            }

            return parent;
        }

        public void RemoveNode(string server, string session)
        {
            TreeNode tn = FindNode(server, session);

            if (tn == null)
                return;

            treeView1.Nodes.Remove(tn);
        }

        private TreeNode FindNode(string server, string session)
        {
            if (treeView1.Nodes.Find(server, false).Count() == 0)
                return null;

            TreeNode tn = treeView1.Nodes.Find(server, false)[0];
            if (tn.Nodes.Find(session, false).Count() == 0)
                return null;

            return tn.Nodes.Find(session, false)[0];
        }

        public void ReloadNode(string server, string session)
        {
            TreeNode tn = FindNode(server, session);

            if (tn == null)
                return;

            ReloadNode(tn);
        }

        private void ReloadNode(TreeNode tn)
        {
            if (tn.Level == 0)
            {
                servers.ToDictionary(s => s.ServerName, s => s)[GetParentNodeByLevel(tn, 0).Name].Refresh();
                //CurrentServer.Refresh();
                BindTreeView(CurrentServer);
            }
            else
            {
                System.Xml.XmlDocument xdoc = servers.ToDictionary(s => s.ServerName, s => s)[GetParentNodeByLevel(tn, 0).Name].EventSessions.Refresh(GetParentNodeByLevel(tn, 1).Name);

                //System.Xml.XmlDocument xdoc = CurrentServer.EventSessions.Refresh(SelectedSession.Name);
               
                XEventTreeNode xtn = (XEventTreeNode)tn;

                xtn.Nodes.Clear();
                xtn.Tag = xdoc.DocumentElement;
                xtn.SelectedImageKey = xtn.getImageKey;
                xtn.ImageKey = xtn.getImageKey;

                
                // SECTION 3. Populate the TreeView with the DOM nodes.
                AddNode(xdoc.DocumentElement, xtn);
                treeView1.Refresh();
            }

        }

        private void EventSession_Load(object sender, EventArgs e)
        {
            UpdateExplorerInfo();

            // Object Explorer SelectionChangedEvent 
            //IObjectExplorerEventProvider provider = (IObjectExplorerEventProvider)ServiceCache.GetObjectExplorer().GetService(typeof(IObjectExplorerEventProvider));
            //provider.SelectionChanged += new NodesChangedEventHandler(Provider_SelectionChanged);
            SetObjectExplorerEventProvider();
            Load_Form();
        }

        private void treeView1_BeforeSelect(object sender, TreeViewCancelEventArgs e)
        {
            //if (MainForm.PropertiesForm.PropertyGrid.SelectedObject != null)
            //{
            //    if (MainForm.PropertiesForm.PropertyGrid.SelectedObject is EventSession)
            //    {
            //        EventSession es = (EventSession)this.MainForm.PropertiesForm.PropertyGrid.SelectedObject;
            //        if (es.IsDirty)
            //        {
            //            DialogResult dr = MessageBox.Show("There are unsaved changes to the currently selected Session.  Do you want to commit these changes to the Server?", "Uncommited Changes", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

            //        }
            //    }
            //}

            //if (this.SelectedSession != null)
            //{
            //    if (this.MainForm.PropertiesForm.PropertyGrid.SelectedObject is EventSession)
            //    {
            //        EventSession es = (EventSession)this.MainForm.PropertiesForm.PropertyGrid.SelectedObject;
            //        if (es.IsDirty)
            //        { }
            //        if (this.SelectedSession.IsDirty)
            //        {
            //            DialogResult dr = MessageBox.Show("There are unsaved changes to the currently selected Session.  Do you want to commit these changes to the Server?", "Uncommited Changes", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

            //        }
            //    }
            //}
        }


        public void SetObjectExplorerEventProvider()
        {
            if (SSMSAddinHelper.ObjectExplorer == null)
                return;
            
            System.Type t = Assembly.Load("SqlWorkbench.Interfaces").GetType("Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer.IObjectExplorerEventProvider");
            if (t != null)
                SetNON2008R2ObjectExplorerEventProvider(t);
            else
                Set2008R2ObjectExplorerEventProvider();
        }


        void SetNON2008R2ObjectExplorerEventProvider(System.Type t)
        {
            // the old way of doing things
            //IObjectExplorerEventProvider objectExplorer = (IObjectExplorerEventProvider)Common.ObjectExplorerService.GetService(typeof(IObjectExplorerEventProvider));
            //objectExplorer.SelectionChanged += new NodesChangedEventHandler(objectExplorer_SelectionChanged);

            MethodInfo mi = this.GetType().GetMethod("Provider_SelectionChanged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            // get the IObjectExplorerEventProvider from the ObjectExplorerService
            object objectExplorer = SSMSAddinHelper.ObjectExplorer.GetService(t);
            EventInfo ei = t.GetEvent("SelectionChanged", System.Reflection.BindingFlags.Public | BindingFlags.Instance);
            // use this overload CreateDelegate(Type type, object firstArgument, MethodInfo method);
            // the 2nd param is "this" because the method to handle the event is in it.
            Delegate del = Delegate.CreateDelegate(ei.EventHandlerType, this, mi);
            ei.AddEventHandler(objectExplorer, del);
        }

        void Set2008R2ObjectExplorerEventProvider()
        {
            // the old way of doing things
            //Microsoft.SqlServer.Management.SqlStudio.Explorer.ObjectExplorerService objectExplorer = Common.ObjectExplorerService as Microsoft.SqlServer.Management.SqlStudio.Explorer.ObjectExplorerService;
            //int nodeCount;
            //INodeInformation[] nodes;
            //objectExplorer.GetSelectedNodes(out nodeCount, out nodes);
            //Microsoft.SqlServer.Management.SqlStudio.Explorer.ContextService contextService = (Microsoft.SqlServer.Management.SqlStudio.Explorer.ContextService)objectExplorer.Container.Components[1];
            //// or ContextService contextService = (ContextService)objectExplorer.Site.Container.Components[1];
            //INavigationContextProvider provider = contextService.ObjectExplorerContext;
            //provider.CurrentContextChanged += new NodesChangedEventHandler(ObjectExplorer_SelectionChanged);

            System.Type t = Assembly.Load("Microsoft.SqlServer.Management.SqlStudio.Explorer").GetType("Microsoft.SqlServer.Management.SqlStudio.Explorer.ObjectExplorerService");
            MethodInfo mi = this.GetType().GetMethod("Provider_SelectionChanged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            int nodeCount;
            INodeInformation[] nodes;
            object objectExplorer = SSMSAddinHelper.ObjectExplorer;
            // hack to load the OE in R2
            (objectExplorer as IObjectExplorerService).GetSelectedNodes(out nodeCount, out nodes);

            PropertyInfo piContainer = t.GetProperty("Container", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
            object objectExplorerContainer = piContainer.GetValue(objectExplorer, null);
            PropertyInfo piContextService = objectExplorerContainer.GetType().GetProperty("Components", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
            //object[] indexArgs = { 1 };
            ComponentCollection objectExplorerComponents = piContextService.GetValue(objectExplorerContainer, null) as ComponentCollection;
            object contextService = null;

            foreach (Component component in objectExplorerComponents)
            {
                if (component.GetType().FullName.Contains("ContextService"))
                {
                    contextService = component;
                    break;
                }
            }
            if (contextService == null)
                throw new Exception("Can't find ObjectExplorer ContextService.");

            PropertyInfo piObjectExplorerContext = contextService.GetType().GetProperty("ObjectExplorerContext", System.Reflection.BindingFlags.Public | BindingFlags.Instance);
            object objectExplorerContext = piObjectExplorerContext.GetValue(contextService, null);

            EventInfo ei = objectExplorerContext.GetType().GetEvent("CurrentContextChanged", System.Reflection.BindingFlags.Public | BindingFlags.Instance);

            Delegate del = Delegate.CreateDelegate(ei.EventHandlerType, this, mi);
            ei.AddEventHandler(objectExplorerContext, del);
        }
    }
}
